/*******************************************************************************************
 *      @name   ai_model.c
 *      @brief  这是在linux系统下的使用HTTP协议对豆包AI大模型进行接入的代码案例
 *      @date   2025/02/26
 *      @author cecelmx@126.com
 *      @note
 *
 *      @version  xx.xx.xx   主版本号.次版本号.修正版本号
 *
 *      CopyRight (c)   2024-2025   Your Name     All Right Reserved
 *
 * ****************************************************************************************/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <netdb.h>

#include "cJSON.h" //包含该头文件

// 缓冲区大小
#define BUFSIZE 2048

// 豆包大模型API的密钥，需要修改为自己的密钥
#define API_KEY "9a65a4fd-6d34-4c87-b3a4-089954973d40"

// HTTP服务的端口
#define HTTP_PORT 80

// 豆包大模型的URL
#define SERVER_URL "/api/v3/chat/completions"

// 豆包大模型的IP
#define SERVER_IP "101.126.75.85"

// 豆包大模型的域名
#define SERVER_DOMAIN "ark.cn-beijing.volces.com"

int main(int argc, char **argv)
{
    // char *recvbuf= calloc(1, BUFSIZ); // 存储响应内容
    // char *request = calloc(1, BUFSIZ); // 存储请求内容
    char recvbuf[BUFSIZ] = {0}; // 存储响应内容
    char request[BUFSIZ] = {0}; // 存储请求内容
    // 1.创建TCP套接字,HTTP协议是基于TCP协议实现的
    int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == tcp_socket)
    {
        fprintf(stderr, "create tcp socket error,%s\n", strerror(errno));
        exit(-1);
    }

    // 2.向豆包大模型的服务器发起连接请求
    struct sockaddr_in dest = {0};               // IPv4地址格式的实例
    dest.sin_family = AF_INET;                   // IPv4协议族
    dest.sin_port = htons(HTTP_PORT);            // 目标端口，需要转换为网络字节序
    dest.sin_addr.s_addr = inet_addr(SERVER_IP); // 目标地址，需要转换为网络字节序

    if (-1 == connect(tcp_socket, (struct sockaddr *)&dest, sizeof(dest)))
    {
        fprintf(stderr, "connect error,%s\n", strerror(errno));
        exit(-2);
    }

    printf("connect ok\n");

#if 1
    for (;;)
    {

        // 3.连接成功后，可以向豆包大模型服务器发起请求，需要构造请求内容
        char reqbody[512] = {0}; // 用于存储请求体

        // 构造请求体，作为POST请求的一部分
        sprintf(reqbody, "{\"model\": \"doubao-1-5-lite-32k-250115\",\"messages\": [{\"role\": \"system\",\"content\": \"你是人工智能助手.\"},"
                         "{\"role\": \"user\",\"content\": \"请告诉我如何在ubuntu下面安装搜狗输入法？\"}]}");

        // 构造POST请求
        sprintf(request, "POST %s HTTP/1.1\r\n"               // 请求行
                         "Host: %s\r\n"                       // 主机域名
                         "Content-Type: application/json\r\n" // 请求体类型
                         "Content-Length: %lu\r\n"            // 请求体长度
                         "Authorization: Bearer %s\r\n"       // 鉴权信息
                         "\n"                                 // 空行
                         "%s\r\n",                            // 请求体内容
                SERVER_URL, SERVER_DOMAIN, strlen(reqbody), API_KEY, reqbody);

        // 输出POST请求，用于调试
        printf("%s\n", request);

        // 4.发送POST请求
        send(tcp_socket, request, strlen(request), 0);
        printf("send ok\n");

        // 5.等待豆包大模型的响应内容  先返回响应头部,再返回响应Body
        sleep(8);
        recv(tcp_socket, recvbuf, sizeof(recvbuf), 0); // 读取响应头部，默认会阻塞
        // printf("[1]%s\n", recvbuf);                    // 输出响应内容

        char *pstr = strstr(recvbuf, "{");

        // 6.把响应体中的JSON格式的字符串进行转换
        cJSON *root = cJSON_Parse(pstr); // 把存储了JSON格式的字符串转换为JSON格式

        char *string = cJSON_Print(root); // 把转换为JSON格式的数据以JSON格式输出

        printf("%s\n", string); // 测试是否成功的把字符串转换为JSON格式

        break;
    }
#endif

    return 0;
}
